/*
REWRITTEN FROM SCRATCH BY PUSSYWIZARD, IT OWNS NOW!
*/

#include "ScriptMgr.h"
#include "ScriptedCreature.h"
#include "oculus.h"
#include "SpellInfo.h"

enum Spells
{
	SPELL_EVOCATION								= 51602,
	SPELL_SUMMON_MENAGERIE_1					= 50476,
	SPELL_SUMMON_MENAGERIE_2					= 50495,
	SPELL_SUMMON_MENAGERIE_3					= 50496,
	SPELL_TELEPORT								= 51112,

	SPELL_FROSTBOMB								= 51103,
	SPELL_TIME_BOMB_N							= 51121,
	SPELL_TIME_BOMB_H							= 59376,
	SPELL_EMPOWERED_ARCANE_EXPLOSION_N			= 51110,
	SPELL_EMPOWERED_ARCANE_EXPLOSION_H			= 59377,
};

#define SPELL_EMPOWERED_ARCANE_EXPLOSION		DUNGEON_MODE(SPELL_EMPOWERED_ARCANE_EXPLOSION_N, SPELL_EMPOWERED_ARCANE_EXPLOSION_H)
#define SPELL_TIME_BOMB							DUNGEON_MODE(SPELL_TIME_BOMB_N, SPELL_TIME_BOMB_H)

enum UromNPCs
{
	NPC_PHANTASMAL_CLOUDSCRAPER					= 27645,
	NPC_PHANTASMAL_MAMMOTH						= 27642,
	NPC_PHANTASMAL_WOLF							= 27644,

	NPC_PHANTASMAL_AIR							= 27650,
	NPC_PHANTASMAL_FIRE							= 27651,
	NPC_PHANTASMAL_WATER						= 27653,

	NPC_PHANTASMAL_MURLOC						= 27649,
	NPC_PHANTASMAL_NAGAL						= 27648,
	NPC_PHANTASMAL_OGRE							= 27647,
};

enum Events
{
	EVENT_FROSTBOMB								= 1,
	EVENT_TELEPORT_TO_CENTER					= 2,
	EVENT_TELE_BACK								= 3,
	EVENT_TIME_BOMB								= 4,
};

enum Yells
{
    SAY_SUMMON_1                                  = 0,
    SAY_SUMMON_2                                  = 1,
    SAY_SUMMON_3                                  = 2,
    SAY_AGGRO                                     = 3,
    EMOTE_ARCANE_EXPLOSION                        = 4,
    SAY_ARCANE_EXPLOSION                          = 5,
    SAY_DEATH                                     = 6,
    SAY_PLAYER_KILL                               = 7
};

float summons[3][4] =	{
							{NPC_PHANTASMAL_AIR, NPC_PHANTASMAL_AIR, NPC_PHANTASMAL_WATER, NPC_PHANTASMAL_FIRE},
							{NPC_PHANTASMAL_OGRE, NPC_PHANTASMAL_OGRE, NPC_PHANTASMAL_NAGAL, NPC_PHANTASMAL_MURLOC},
							{NPC_PHANTASMAL_CLOUDSCRAPER, NPC_PHANTASMAL_CLOUDSCRAPER, NPC_PHANTASMAL_MAMMOTH, NPC_PHANTASMAL_WOLF}
						};

float cords[4][4] =		{
							{1177.47f, 937.722f, 527.405f, 2.21657f},
							{968.66f, 1042.53f, 527.32f, 0.077f},
							{1164.02f, 1170.85f, 527.321f, 3.66f},
							{1118.31f, 1080.377f, 508.361f, 4.25f}
						};

class boss_urom : public CreatureScript
{
public:
    boss_urom() : CreatureScript("boss_urom") { }

    CreatureAI* GetAI(Creature* pCreature) const
    {
        return new boss_uromAI (pCreature);
    }

	struct boss_uromAI : public ScriptedAI
	{
		boss_uromAI(Creature *c) : ScriptedAI(c)
		{
			pInstance = c->GetInstanceScript();
		}
		
		InstanceScript* pInstance;
		EventMap events;
		bool lock;
		float x,y,z;
		int32 releaseLockTimer;

		uint8 GetPhaseByCurrentPosition()
		{
			for (uint8 i=0; i<4; ++i)
				if (me->GetDistance(cords[i][0], cords[i][1], cords[i][2]) < 20.0f)
					return i;

			return 0;
		}

		void Reset()
		{
			if (pInstance)
			{
				pInstance->SetData(DATA_UROM, NOT_STARTED);
				if( pInstance->GetData(DATA_VAROS) != DONE )
					me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE);
				else
					me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE);
			}

			me->CastSpell(me, SPELL_EVOCATION, true);
			events.Reset();
			lock = false;
			x,y,z = 0.0f;
			releaseLockTimer = 0;
			me->ApplySpellImmune(0, IMMUNITY_ID, 49838, true);
		}

		void EnterCombat(Unit* who)
		{
			if( lock )
				return;

			uint8 phase = GetPhaseByCurrentPosition();
			if( phase == 3 )
			{
				Talk(SAY_AGGRO);

				if( pInstance )
					pInstance->SetData(DATA_UROM, IN_PROGRESS);

				me->SetInCombatWithZone();
				me->SetHomePosition(cords[0][0], cords[0][1], cords[0][2], cords[0][3]);
				if( me->FindCurrentSpellBySpellId(SPELL_EVOCATION) )
					me->InterruptNonMeleeSpells(false);

				events.RescheduleEvent(EVENT_FROSTBOMB, urand(7000, 11000));
				events.RescheduleEvent(EVENT_TELEPORT_TO_CENTER, urand(30000, 35000));
				events.RescheduleEvent(EVENT_TIME_BOMB, urand(20000, 25000));
			}
			else
			{
				lock = true;

				switch( phase )
				{
					case 0:
						Talk(SAY_SUMMON_1);
						me->InterruptNonMeleeSpells(false);
						me->CastSpell(me, SPELL_SUMMON_MENAGERIE_1, false);
						break;
					case 1:
						Talk(SAY_SUMMON_2);
						me->InterruptNonMeleeSpells(false);
						me->CastSpell(me, SPELL_SUMMON_MENAGERIE_2, false);
						break;
					case 2:
						Talk(SAY_SUMMON_3);
						me->InterruptNonMeleeSpells(false);
						me->CastSpell(me, SPELL_SUMMON_MENAGERIE_3, false);
						break;
				}
			}
		}

		void AttackStart(Unit* who)
		{
			if( lock )
				return;

			if (me->GetDistance(1103.0f, 1049.0f, 510.0f) < 55.0f)
				ScriptedAI::AttackStart(who);
		}

		void JustSummoned(Creature* pSummon)
		{
			pSummon->SetInCombatWithZone();
			if( Unit* v = pSummon->SelectVictim() )
				if( pSummon->AI() )
					pSummon->AI()->AttackStart(v);
		}

		void LeaveCombat()
		{
			me->RemoveAllAuras();
			me->DeleteThreatList();
			me->CombatStop(true);
			me->LoadCreaturesAddon(true);
			me->SetLootRecipient(NULL);
			me->ResetPlayerDamageReq();
		}

		void JustDied(Unit* killer)
		{
			Talk(SAY_DEATH);

			if (pInstance)
				pInstance->SetData(DATA_UROM, DONE);
		}

		void KilledUnit(Unit *victim)
		{
			Talk(SAY_PLAYER_KILL);
		}

		void SpellHit(Unit* caster, const SpellInfo* spell)
		{
			switch( spell->Id )
			{
				case SPELL_SUMMON_MENAGERIE_1:
				case SPELL_SUMMON_MENAGERIE_2:
				case SPELL_SUMMON_MENAGERIE_3:
					{
						me->DestroyForNearbyPlayers();
						uint8 phase = GetPhaseByCurrentPosition();
						for( uint8 i=0; i<4; ++i )
							me->SummonCreature(summons[phase][i], cords[phase][0] + ((i%2) ? 4.0f : -4.0f), cords[phase][1] + (i<2 ? 4.0f : -4.0f), cords[phase][2], 0.0f, TEMPSUMMON_TIMED_DESPAWN, 300000);
						me->SetHomePosition(cords[phase+1][0], cords[phase+1][1], cords[phase+1][2], cords[phase+1][3]);
						LeaveCombat();
						me->CastSpell(me, SPELL_EVOCATION, true);
						releaseLockTimer = 1;
					}
					break;
				case SPELL_TELEPORT:
					me->GetMotionMaster()->Clear();
					me->GetMotionMaster()->MoveIdle();
					me->StopMoving();
					me->SetControlled(true, UNIT_STATE_ROOT);
					me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE);
					me->SetCanFly(true);
					me->SetDisableGravity(true);
					me->NearTeleportTo(1103.69f, 1048.76f, 512.279f, 1.16f);
					
					Talk(SAY_ARCANE_EXPLOSION);
					Talk(EMOTE_ARCANE_EXPLOSION);

					me->CastSpell(me, SPELL_EMPOWERED_ARCANE_EXPLOSION, false);
					events.RescheduleEvent(EVENT_TELE_BACK, DUNGEON_MODE(9000, 7000));
				default:
					break;
			}
		}

		void MoveInLineOfSight(Unit* who) {}

		void UpdateAI(uint32 diff)
		{
			if( releaseLockTimer )
			{
				if( releaseLockTimer >= 5000 )
				{
					lock = false;
					if (me->IsInCombat())
					{
						LeaveCombat();
						me->CastSpell(me, SPELL_EVOCATION, true);
					}
					releaseLockTimer = 0;
				}
				else
					releaseLockTimer += diff;
			}

			if( !UpdateVictim() )
				return;

			events.Update(diff);

			if( me->HasUnitState(UNIT_STATE_CASTING) )
				return;

			DoMeleeAttackIfReady();

			switch( events.GetEvent() )
			{
				case 0:
					break;
				case EVENT_FROSTBOMB:
					if( Unit* v = me->GetVictim() )
						me->CastSpell(v, SPELL_FROSTBOMB, false);
					events.RepeatEvent(urand(7000,11000));
					break;
				case EVENT_TIME_BOMB:
					if( Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 100.0f, true) )
						me->CastSpell(target, SPELL_TIME_BOMB, false);
					events.RepeatEvent(urand(20000, 25000));
					break;
				case EVENT_TELEPORT_TO_CENTER:
					x = me->GetPositionX();
					y = me->GetPositionY();
					z = me->GetPositionZ();
					me->CastSpell(me, SPELL_TELEPORT, false);
					events.RepeatEvent(urand(25000,30000));
					events.DelayEvents(10000);
					break;
				case EVENT_TELE_BACK:
					me->GetMotionMaster()->MoveIdle();
					me->DisableSpline();
					me->SetCanFly(false);
					me->SetDisableGravity(false);
					me->NearTeleportTo(x, y, z, 0.0f);
					me->SetControlled(false, UNIT_STATE_ROOT);
					me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE);
					me->GetMotionMaster()->MoveChase(me->GetVictim());
					events.PopEvent();
					break;
			}
		}

		void EnterEvadeMode()
		{
			me->SetCanFly(false);
			me->SetDisableGravity(false);
			me->SetControlled(false, UNIT_STATE_ROOT);
			ScriptedAI::EnterEvadeMode();
		}
	};
};

void AddSC_boss_urom()
{
	new boss_urom();
}
